package com.yun.redis.practice;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * Created by lsy
 * on 2019/12/11 15:02.
 */
public class RedisLock {


    // 加锁方法，使用setnx设置一个键
    public static String acquire(String lockName, int timeout) {
        Jedis conn = RedisUtils.getConnection();
        String token = UUID.randomUUID().toString();
        int count = 10;
        String lock = "lock:" + lockName;
        while (count >= 0) {
            Long result = conn.setnx(lock, token);
            if (result == 1L) {
                // 设置失败，可能是别人的锁代码中断没有设置超时
                Long ttl = conn.ttl(lock);
                if (ttl == -1) {
                    conn.expire(lock, timeout);
                }
                return token;
            }
            conn.expire(lock, timeout);
            // 获取失败
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
        }
        return null;
    }

    public static boolean release(String lockName, String token) {
        Jedis conn = RedisUtils.getConnection();
        String lock = "lock:" + lockName;
        while (true) {
            conn.watch(lock);
            String t = conn.get(lock);
            if (token.equals(t)) {
                Transaction multi = conn.multi();
                multi.del(lock);
                List<Object> exec = multi.exec();
                if (exec == null) {
                    continue;
                }
                return true;
            }
            conn.unwatch();
            break;
        }
        // 不是自己加的锁
        return false;
    }

    public static void main(String[] args) {
        String token1 = RedisLock.acquire("story", 100);
        String token2 = RedisLock.acquire("story", 100);
        System.out.println(token1);
        System.out.println(token2);

        boolean story1 = RedisLock.release("story",token1);
        boolean story2 = RedisLock.release("story", token2);
        System.out.println(story1);
        System.out.println(story2);
    }
}
